/* 
 * File:   Vocabluary.cpp
 * Author: vicror
 * 
 * Created on October 24, 2011, 12:54 AM
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "Vocabluary.h"
#include "SearchEnginer.h"
#include <algorithm>
#include <iostream>
namespace SearchEnginer {

    std::vector<Vocabluary *> Vocabluary::listVoc;

    Vocabluary::Vocabluary() {
    }

    Vocabluary::Vocabluary(const Vocabluary& /*orig*/) {
    }

    Vocabluary::~Vocabluary() {
    }

    void Vocabluary::link(Base_SearchEnginer& orig) {
        std::vector<Vocabluary * >::iterator itr = listVoc.begin();
        while(itr != listVoc.end() && !(*itr)->removeSearchEnginer(orig)) ++itr;
        if (itr != listVoc.end()) {
            removeVocabluary(*(*itr));
        }
        listSE.push_back(static_cast<Base_SearchEnginer * >(&orig));
        orig.syncVocabluary(this);
        Index ind = 0;
        // Заполняем поисковую машину словами
        for (ListStringConstItr itr = vocabluary.begin();
                itr != vocabluary.end(); ++itr) {
            orig.syncWord(*itr, ind++);
        }
    }

    void Vocabluary::unlink(Base_SearchEnginer& orig) {
        if (removeSearchEnginer(orig))  removeVocabluary(*this);
    }

    Vocabluary * Vocabluary::Init(Base_SearchEnginer& orig) {
        Vocabluary *res = new Vocabluary;
        listVoc.push_back(res);
        res->link(orig);
        return res;

    }
    
    int Vocabluary::hasSearchEnginer(const Base_SearchEnginer& orig) const {
        int res =0;
        while(res < static_cast<int>(listSE.size()) && listSE[res] != &orig) res++;
        if (res == static_cast<int>(listSE.size())) res = -1;
        return res;
    }

    bool Vocabluary::removeSearchEnginer(Base_SearchEnginer& orig) {
        bool res = false;
        int index = hasSearchEnginer(orig);
        if (index >= 0) {
            res = true;
            listSE.erase(listSE.begin() + index);
            orig.syncUnLink();
        }
        return res;
    }

    void Vocabluary::removeVocabluary(Vocabluary& orig) {
        int index = 0;
        while(index < static_cast<int>(listVoc.size()) &&
              listVoc[index] != &orig) index++;
        if (index != static_cast<int>(listVoc.size())) {
            Vocabluary *temp = listVoc[index];
            if (temp->listSE.size() == 0) {
                listVoc.erase(listVoc.begin() + index);
                delete temp;
            }
        }
    }

    bool Vocabluary::append(const Vocabluary& orig) {
        bool res = false;
        ListStringConstItr itr = orig.vocabluary.begin();
        for(; itr != orig.vocabluary.end(); ++itr) {
            res |= append(*itr);
        }
        return res;
    }

    bool Vocabluary::append(const string& orig) {
        bool res = false;
        ListIndex list = hasWordByIndex(orig);
        ListIndexConstItr itr = list.begin();
        while(itr != list.end() && vocabluary[*itr] != orig) ++itr;
        if (itr == list.end()) {
            Index ind = vocabluary.size();
            vocabluary.push_back(orig);
            res = true;
            for(ListSearchEnginerItr itr = listSE.begin();
                itr != listSE.end(); ++itr) {
                (*itr)->syncWord(orig, ind);
            }
        }
        return res;
    }

    ListIndex Vocabluary::hasWordByIndex(const string& orig) {
        ListIndex res;
        ListIndex work;
        for(ListSearchEnginerItr itr = listSE.begin(); itr != listSE.end(); ++itr) {
            ListIndex temp = (*itr)->hasWordByID(orig);
            for(ListIndexConstItr inde=temp.begin(); inde != temp.end(); ++inde) {
                work.push_back(*inde);
            }
        }
        std::sort(work.begin(), work.end());
        Index i = -1;
        for(ListIndexConstItr inde=work.begin(); inde != work.end(); ++inde) {
            if ((*inde) != i) {
                i = (*inde);
                res.push_back(i);
            }
        }

        return res;
    }

    const string metka("SearchEnginerVer1.0");

    std::ostream& operator<< (std::ostream& out, const Vocabluary &orig) {
       out << metka << std::endl;
       for(ListStringConstItr itr = orig.vocabluary.begin();
               itr != orig.vocabluary.end(); ++itr) {
           out << *itr << std::endl;
       }
       return out;
    }

    std::istream& operator>> (std::istream& is, Vocabluary& orig) {
        string temp;
        if (!is.eof()) {
            is >> temp;
            if (temp == metka) {
                while(!is.eof()) {
                    is >> temp;
                    orig.append(temp);
                }
            }
        }
        return is;
    }

    ListString Vocabluary::getWords() const {
        return vocabluary;
    }

    ListString Vocabluary::getWords(const ListIndex& orig) const {
        ListString temp;
        temp.reserve(orig.size());
        int size = vocabluary.size();
        ListIndexConstItr itr = orig.begin();
        while(itr != orig.end()) {
            if (((*itr) >= 0) && ((*itr) < size)) {
                temp.push_back(vocabluary[*itr]);
            }
            ++itr;
        }
        return temp;
    }

    unsigned int Vocabluary::size(void) const {
        return vocabluary.size();
    }

}
